#pragma once 
#include<iostream>
#include"log.hpp"
#include<queue>
#include<pthread.h>
#include"Task.hpp"
#define NUM 6
class ThreadPool
{
  private:
    int num;
    bool stop;
    std::queue<Task> task_queue;
    pthread_mutex_t lock;
    pthread_cond_t cond;
    ThreadPool(int _num=NUM):num(_num),stop(false)
    {
        pthread_mutex_init(&lock,nullptr);
        pthread_cond_init(&cond,nullptr);
    }
    ThreadPool(const ThreadPool&)=delete;
    static ThreadPool* single_instance;
  public:
    static ThreadPool* GetInstance()
    {
      static pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
      if(single_instance==nullptr)
      {
        pthread_mutex_lock(&mutex);
        if(single_instance==nullptr)
        {
          single_instance=new ThreadPool();
          single_instance->InitThreadPool();
        }
        pthread_mutex_unlock(&mutex);
      }
      return single_instance;
    }
    bool IsStop()
    {
      return stop;
    }
    void Lock()
    {
      pthread_mutex_lock(&lock);
    }
    void Unlock()
    {
      pthread_mutex_unlock(&lock);
    }
    bool TaskQueueIsEmpty()
    {
      return task_queue.size()==0?true:false;
    }
    void ThreadWait()
    {
      pthread_cond_wait(&cond,&lock);
    }
    void ThreadWakeup()
    {
      pthread_cond_signal(&cond);
    }
    void PopTask(Task& out)
    {
      out=task_queue.front();
      task_queue.pop();
    }
    void PushTask(const Task &in)
    {
      Lock();
      task_queue.push(in);
      Unlock();
      ThreadWakeup();
    }
    static void* ThreadRoutine(void* args)
    {
        ThreadPool* tp=(ThreadPool*) args;
        while(true)
        {
          Task t;
          tp->Lock();
          while(tp->TaskQueueIsEmpty())
          {
            tp->ThreadWait();
          }
          tp->PopTask(t);
          tp->Unlock();
          t.ProcessOn();
        }
    }
    bool InitThreadPool()
    {
      for(int i=0;i<num;i++)
      {
        pthread_t tid;
        if(pthread_create(&tid,nullptr,ThreadRoutine,this)!=0)
        {
            LOG(FATAL,"create thread pool error!");
            return false;
        }
      }
      return true;
    }
    ~ThreadPool()
    {
      pthread_mutex_destroy(&lock);
      pthread_cond_destroy(&cond);
    }
};
ThreadPool* ThreadPool::single_instance=nullptr;
